From f7db731e2fe453a40d9a650b8394177c7da7a6ba Mon Sep 17 00:00:00 2001 From: oliskoli Date: Thu, 30 Oct 2008 22:38:19 +0000 Subject: [PATCH] Add new format 'skyforce'. --- Makefile.in | 5 +- skyforce.c | 353 ++++++++++++++++++++++++++++++++++++++++++++++++++++ testo | 18 ++- vecs.c | 7 ++ 4 files changed, 381 insertions(+), 2 deletions(-) create mode 100644 skyforce.c diff --git a/Makefile.in b/Makefile.in index 5bf16d6d5..52818210c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -61,7 +61,7 @@ ALL_FMTS=$(MINIMAL_FMTS) gtm.o gpsutil.o pcx.o cetus.o copilot.o \ ggv_log.o g7towin.o garmin_gpi.o lmx.o random.o xol.o dg-100.o \ navilink.o mtk_logger.o ik3d.o osm.o destinator.o exif.o vidaone.o \ igo8.o gopal.o humminbird.o mapasia.o gnav_trl.o navitel.o ggv_ovl.o \ - jtr.o sbp.o mmo.o + jtr.o sbp.o mmo.o skyforce.o FMTS=@FMTS@ @@ -752,6 +752,9 @@ session.o: session.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ shape.o: shape.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h session.h \ shapelib/shapefil.h +skyforce.o: skyforce.c defs.h config.h queue.h gbtypes.h \ + zlib/zlib.h zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h session.h \ + pdbfile.h smplrout.o: smplrout.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h session.h filterdefs.h \ grtcirc.h diff --git a/skyforce.c b/skyforce.c new file mode 100644 index 000000000..910f2636b --- /dev/null +++ b/skyforce.c @@ -0,0 +1,353 @@ +/* + + Support for SkymapII / SkymapIIIC & KMD150 ascii files + + Copyright (C) 2008 Olaf Klein, o.b.klein@gpsbabel.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA + + */ + + +#include "defs.h" +#include +#include +#include "strptime.h" + + +#define MYNAME "skyforce" + + +static +arglist_t skyforce_args[] = { + ARG_TERMINATOR +}; + +static gbfile *fin, *fout; +static int rte_num, wpt_num; +static short_handle short_h; +static const waypoint *prev_wpt; + + +static waypoint * +skyforce_parse_coords(const char *str) +{ + waypoint *wpt; + + if (strlen(str) < 38) fatal(MYNAME ": Incomplete line!\n"); + + wpt = waypt_new(); + + wpt->latitude = atof(str + 21); + if (str[20] == 'S') wpt->latitude = -wpt->latitude; + wpt->latitude = ddmm2degrees(wpt->latitude); + + wpt->longitude = atof(str + 30); + if (str[29] == 'W') wpt->longitude = -wpt->longitude; + wpt->longitude = ddmm2degrees(wpt->longitude); + + return wpt; +} + + +static waypoint * +skyforce_parse_wpt(const char *str, int *rte_num) +{ + waypoint *wpt; + + wpt = skyforce_parse_coords(str); + if (wpt == NULL) return NULL; + + wpt->shortname = lrtrim(xstrndup(str + 10, 9)); + + if (rte_num) *rte_num = atoi(str + 2); + + return wpt; +} + + +static waypoint * +skyforce_parse_trk(const char *str) +{ + char *cx; + struct tm tm; + char buf[15]; + int len; + + waypoint *wpt; + + wpt = skyforce_parse_coords(str); + if (wpt == NULL) return NULL; + + memset(&tm, 0, sizeof(tm)); + strncpy(buf, str + 2, sizeof(buf) - 1); + + cx = strptime(buf, "%d%m%y %H%M%S ", &tm); + if ((cx != NULL) && (*cx != '\0')) + fatal(MYNAME ": Could not parse date string (%s - %s).\n", buf, cx); + + wpt->creation_time = mkgmtime(&tm); + + len = strlen(str); + + if (len >= 45) WAYPT_SET(wpt, speed, KNOTS_TO_MPS(atof(str + 39))); + if (len >= 59) { + wpt->altitude = FEET_TO_METERS(atof(str + 54)); + if (str[53] == '-') wpt->altitude = -wpt->altitude; + } + + return wpt; +} + + +static void +skyforce_head_disp_cb(const route_head *head) +{ + prev_wpt = NULL; + if (head->rte_waypt_ct <= 0) return; + + wpt_num = 0; + rte_num++; + + if (rte_num > 999) { + if (rte_num == 1000) warning(MYNAME ": Can't store more than 999 routes. Some routes skipped!\n"); + return; + } +} + + +static void +skyforce_waypt_disp_cb(const waypoint *wpt) +{ + char buf[75]; /* long enough for all data types */ + double lat, lon; + + + memset(buf, ' ', sizeof(buf)); + buf[sizeof(buf) - 1] = '\0'; + + switch(global_opts.objective) { + case wptdata: buf[0] = 'W'; break; + case trkdata: buf[0] = 'L'; break; + case rtedata: buf[0] = 'R'; break; + default: ; /* should never happen */ + } + + if (global_opts.objective == trkdata) { + struct tm tm; + + tm = *gmtime(&wpt->creation_time); + strftime(buf + 2, sizeof(buf) - 2, "%d%m%y %H%M%S ", &tm); + } + else { + char *name; + + if (rte_num > 999) return; + + wpt_num++; + if (wpt_num > 999) { + if (wpt_num == 1000) + warning(MYNAME ": Can't store more than 999 waypoints. Some waypoints skipped!\n"); + return; + } + if (global_opts.synthesize_shortnames) + name = mkshort_from_wpt(short_h, wpt); + else + name = mkshort(short_h, wpt->shortname); + + if (global_opts.objective == rtedata) + snprintf(buf + 2, sizeof(buf) - 2, "%03d ", rte_num); + snprintf(buf + 6, sizeof(buf) - 6, "%03d %-9s ", wpt_num, name); + } + + + lat = degrees2ddmm(wpt->latitude); + buf[20] = (wpt->latitude < 0) ? 'S' : 'N'; + snprintf(&buf[21], sizeof(buf) - 21, "%06.2f ", fabs(lat)); + + lon = degrees2ddmm(wpt->longitude); + buf[29] = (wpt->longitude < 0) ? 'W' : 'E'; + snprintf(&buf[30], sizeof(buf) - 30, "%08.2f ", fabs(lon)); + + if (global_opts.objective == trkdata) { + double alt, speed; + + if (wpt->altitude == unknown_alt) alt = 0; + else alt = METERS_TO_FEET(wpt->altitude); + speed = MPS_TO_KNOTS(waypt_speed(prev_wpt, wpt)); + + snprintf(&buf[39], sizeof(buf) - 39, "%06.2f 000.00 %c%05d", + speed, + alt < 0 ? '-' : '+', si_round(fabs(alt))); + } + + rtrim(buf); + gbfprintf(fout, "%s\n", buf); + + prev_wpt = wpt; +} + +/******************************************************************************* +* %%% global callbacks called by gpsbabel main process %%% * +*******************************************************************************/ + +static void +skyforce_rd_init(const char *fname) +{ + fin = gbfopen(fname, "r", MYNAME); +} + + +static void +skyforce_rd_deinit(void) +{ + gbfclose(fin); +} + + +static void +skyforce_read(void) +{ + char *str; + route_head *rte, *trk; + + wpt_num = 0; + rte = trk = NULL; + rte_num = -1; + + while ((str = gbfgetstr(fin))) { + + waypoint *wpt; + int i; + + str = lrtrim(str); + if (*str == '\0') continue; + + switch(*str) { + + case 'W': + wpt = skyforce_parse_wpt(str, NULL); + if (wpt == NULL) continue; + waypt_add(wpt); + break; + + case 'R': + wpt = skyforce_parse_wpt(str, &i); + if (wpt == NULL) continue; + + if (i != rte_num) { + rte_num = i; + rte = NULL; + } + + if (rte == NULL) { + rte = route_head_alloc(); + route_add_head(rte); + rte->rte_num = rte_num; + } + route_add_wpt(rte, wpt); + break; + + case 'L': + wpt = skyforce_parse_trk(str); + if (wpt == NULL) continue; + if (trk == NULL) { + trk = route_head_alloc(); + track_add_head(trk); + } + track_add_wpt(trk, wpt); + break; + + default: + fatal(MYNAME ": Invalid line marker '%c'!\n", *str); + } + } +} + + +static void +skyforce_wr_init(const char *fname) +{ + fout = gbfopen(fname, "w", MYNAME); + + short_h = mkshort_new_handle(); + + setshort_length(short_h, 9); + setshort_badchars(short_h, "\r\n\t"); + setshort_mustupper(short_h, 1); + setshort_mustuniq(short_h, 1); + setshort_whitespace_ok(short_h, 0); + setshort_repeating_whitespace_ok(short_h, 0); + + wpt_num = 0; + rte_num = 0; +} + + +static void +skyforce_wr_deinit(void) +{ + mkshort_del_handle(&short_h); + gbfclose(fout); +} + + +static void +skyforce_write(void) +{ + switch(global_opts.objective) { /* We can only write one data type at a time */ + + case wptdata: + setshort_defname(short_h, "WPT"); + waypt_disp_all(skyforce_waypt_disp_cb); + break; + + case rtedata: + setshort_defname(short_h, "RTE"); + setshort_mustuniq(short_h, 0); + route_disp_all(skyforce_head_disp_cb, NULL, skyforce_waypt_disp_cb); + break; + + case trkdata: + track_disp_all(skyforce_head_disp_cb, NULL, skyforce_waypt_disp_cb); + break; + + case posndata: + fatal(MYNAME ": Realtime positioning not supported.\n"); + break; + + default: + fatal(MYNAME ": Unknown data mode!\n"); + } +} + + +/**************************************************************************/ + +ff_vecs_t skyforce_vecs = { + ff_type_file, + FF_CAP_RW_ALL, /* read and write waypoints, tracks and routes*/ + skyforce_rd_init, + skyforce_wr_init, + skyforce_rd_deinit, + skyforce_wr_deinit, + skyforce_read, + skyforce_write, + NULL, + skyforce_args, + CET_CHARSET_ASCII, 1 +}; + +/**************************************************************************/ diff --git a/testo b/testo index 577aa53ff..102d33563 100755 --- a/testo +++ b/testo @@ -9,7 +9,7 @@ export MALLOC_CHECK_ PNAME=${PNAME:-./gpsbabel} DIFF=${DIFF:-diff} -BASEPATH=$(dirname $0) +BASEPATH=`dirname $0` REFERENCE=${BASEPATH}/reference # OD=${OD:-od -Ax -txC -v} if [ -x /usr/bin/hexdump ] ; then @@ -1527,5 +1527,21 @@ compare ${REFERENCE}/memory-map~mmo.gpx ${TMPDIR}/memory-map~mmo.gpx gpsbabel -i gpx -f ${REFERENCE}/memory-map~mmo.gpx -o mmo -F ${TMPDIR}/memory-map~mmo.mmo gpsbabel -i mmo -f ${TMPDIR}/memory-map~mmo.mmo -o gpx -F ${TMPDIR}/memory-map~mmo~gpx.mmo +# +# Skyforce ascii files +# +gpsbabel -i skyforce -f ${REFERENCE}/skyforce_wpt.txt -o gpx -F ${TMPDIR}/skyforce_wpt.gpx +compare ${REFERENCE}/skyforce_wpt.gpx ${TMPDIR}/skyforce_wpt.gpx +gpsbabel -i skyforce -f ${REFERENCE}/route/skyforce_rte.txt -o gpx -F ${TMPDIR}/skyforce_rte.gpx +compare ${REFERENCE}/route/skyforce_rte.gpx ${TMPDIR}/skyforce_rte.gpx +gpsbabel -i skyforce -f ${REFERENCE}/track/skyforce_trk.txt -o gpx -F ${TMPDIR}/skyforce_trk.gpx +compare ${REFERENCE}/track/skyforce_trk.gpx ${TMPDIR}/skyforce_trk.gpx + +gpsbabel -i skyforce \ + -f ${REFERENCE}/skyforce_wpt.txt \ + -f ${REFERENCE}/route/skyforce_rte.txt \ + -f ${REFERENCE}/track/skyforce_trk.txt -o gpx -F ${TMPDIR}/skyforce.gpx +compare ${REFERENCE}/skyforce.gpx ${TMPDIR}/skyforce.gpx + exit 0 diff --git a/vecs.c b/vecs.c index cebe19762..0e0863cec 100644 --- a/vecs.c +++ b/vecs.c @@ -152,6 +152,7 @@ extern ff_vecs_t jtr_vecs; #endif extern ff_vecs_t sbp_vecs; extern ff_vecs_t mmo_vecs; +extern ff_vecs_t skyforce_vecs; static vecs_t vec_list[] = { @@ -869,6 +870,12 @@ vecs_t vec_list[] = { "Memory-Map Navigator overlay files (.mmo)", "mmo" }, + { + &skyforce_vecs, + "skyforce", + "Skymap / KMD150 ascii files", + NULL + }, #endif // MAXIMAL_ENABLED -- 2.30.2